iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 3
0
Mobile Development

諸神黃昏下的 iOS 工程師系列 第 3

D3 - 簡單寫個配置,不再害怕修修改改

  • 分享至 

  • xImage
  •  

簡單寫個配置,加快開發速度,減少修改的成本

? 隕石小故事

身為一個隕石開發工程師,常常在改變設置是一件理所當然的事情,上頭要求什麼我們就變成什麼(神說要有光,就有了光)。

舉幾個例子來說,像是 APP 的整體配色(我們就改了 3、4 次)或是圓角不明顯,動畫效果不一樣快等等,其他各位客官自行腦補。因此,我們需要把這些統一的設定記錄在某個地方,其他人參考這些設定即可,如此一來,再也不用害怕修修改改了。

Overview

其實這篇文章要講的事情很簡單,其實就是一些在開發專案上的小技巧,因為專案會變動是一件很正常的事情,只是要怎麼讓這些變動用最小的力氣解決,也就是讓我們改的成本(時間)減少。因此這次就來教大家一些我在開發專案時的小技巧吧。

因為身為 iOS 工程師,所以文章中的一些方式可能就是採用 iOS 的特性或是 iOS 才有的功能來實作,但我相信這些概念在其他程式語言通用,也能夠用其他的方式時做出相同的效果的。


配置實作

|顏色配置

相信在開發專案的時候,常常有很多時候都在調整元件的顏色上,因為每個元件都可能有一個顏色,但這些顏色可能都是固定的,所以在這邊我們會為這些顏色來建立簡單的配置。

在這邊,我們可以使用 extension 的方式來設定我們 App 中所需的顏色,我們可以為這些顏色命名,像是主要顏色、次要顏色、按鈕顏色或陰影顏色等等,根據你的需求來命名:

如此一來我們在選配顏色的時候一樣可以透過 UIColor. 來選擇我們剛剛所 extension 的靜態常數:

因為所有顏色都會參考某個常數,所以之後如果主要顏色要改動,我們只需要改動 primaryColor 那麼 App 整體的主要顏色就會被改動了,不需要再一個一個手動慢慢修改了。

你也可以額外建立一個 enum 來存放這些靜態變數:

這樣使用的時候必須要加上該 enum 的名稱才能使用:


|將常用的值存到常數屬性中使用

常常我們在寫一些需要動態計算尺寸的地方時,可能會寫了一些什麼 width + (10 x 3)) / 2 之類 hard code的程式碼,但是其實我們除了 width 之外,我們不曉得其他數字代表著什麼,因此我們可以把一些值存到一些常數中方便使用,同時也了解他代表什麼。

下面我們示範一個沒有創建常數的版本,這邊是我們在製作一個 9 宮格的 CollectionView,其中幾段程式碼區段:

numberOfItemsInSection 因為是九宮格所以可能 (3 * 3) 或是 9 還能夠明白他的意思。但是在 sizeForItemAt 的地方,其中在計算 length 的時候寫了 collectionView.bounds.width - (5 * CGFloat(3 - 1)) / 3 一長串的程式碼,我們不懂其中的每個數字代表著什麼,只能夠大該猜出他是想要計算出一行 3 個 cell 的寬度。

因此我們可以宣告一些常數來處理這些數據,這邊我們先新增以下屬性:

我們創建了行(row)、列(colume)以及間距(spacing)的常數屬性,接這我們在剛剛上面的程式碼區段中使用它們:

看一下畫面:

如此一來我們就能夠輕易了解其中每個值是如何被計算出來的,加上我們不適用 hard code 的方式來輸入值,所以我們可以變動任何值,假設我們把 rows 改成 10columns 改成 5spaceing 改成 1,我們也不需要調整任何項目,直接運行即可:

當然如果你有些 String 類型的值可能常常使用到的話,你也能夠使用一個常數屬性來管理他們,不僅能夠透過該常數名稱來了解是什麼,同時也防止了可能輸入錯誤的狀況。


|使用 Enum 管理程式碼(TableView/CollectionView)

在 iOS 開發中,使用 UITableView 或是 UICollectionView 來開發是很常見的,而我們常常會根據其 section 或 row 來區分該 IndexPath 位置的 cell 該怎麼呈現,但 section 和 row 分別來看都只是一個單純的整數值,在我們進行 switch 的時候總是需要加上 default,並且想要更換 section 或 row 的順序時,總是會把程式碼剪來剪去的。因此我們需要讓這些數字有明顯的名稱來區分它們。

很幸運的我們有 enum 這個強大的類型可以使用,我們可以藉由在 enum 後面標記 Int,讓可以透過 rawValue 產生我們 enum 的類型。

我們下面示範一個範例,該設計圖有分為 banner, news, products 以及 footer 的區塊,我們會根據這些內容來定義一個 enum 名為 Section

接著我們創建一個名為 sections 的 Array,類型為剛剛所建立的 [Section] 。(懶惰一點可以使用 Section.allCase)

這邊我們 UITableViewDataSource 的程式碼會變成這樣,順便用一下之前所新增的顏色:

這邊你能夠很清楚的看到每個 case 做了什麼相對應的事情,接著讓我們運行一下程式碼:

這時如果想要改變介面,想要變成有兩個 banner 跟三個 product,同時移除 news,並且把 footer 移至最上面。這時,我們只要把我們 section 中的內容按照需求改變即可,所以我們的 sections 會變成:

這時我們只要直接在運行一次程式碼即可,不需改動任何程式碼:

如此一來無論區塊怎麼調整,對我們來說只需要簡單調整 sections 的內容即可,大大減少了修改時的成本。


|使用統一的方式來客製化元件

在同一個專案中,可能許多的風格或是顏色都很雷同或是一模一樣,這時候我們可以寫一個方法統一管理這些元件,例如有幾個按鈕在不同畫面上都長得一樣,需要切圓型的圓角、白色框線然後黑底白字,這時我們可以為他撰寫個方法來產生它:

接著我們只需要讓我們的按鈕執行 button.customized() 即可,讓我們運行看看結果吧:

當然並不是所有元件都是套用同一個模板,可能某些地方會有些不同,這時候你可以為這些不同的地方,使用參數方式帶入新值來改變它。像是我們想要我們客製化的按鈕可以自行修改標題、背景色以及框線寬度,我們可以把上面 cutsomized 函數改成這樣:

這時候再回到我們想要客製化按鈕的地方,你會發現我們可以使用 customized 函數來做許多不同的調整,而沒有輸入參數的地方則會使用我們預設的默認值。像是如果沒輸入 backgroundColor 那麼就會默認為 .blackborderWidth 則是 1

如此一來我們可以用一個方法來創建不同的客製化元件。當然你也是能使用 enum 來管理不同 style 的按鈕:

接著我們一樣就能夠透過 setupButton 這個函數來設置我們的按鈕:

接著我們運行一下也能獲得想要的結果:

當然上述這些操作你也能夠定義一些 subClass 來做管理也是很實用的。你還能夠使用 @IBDesignable@IBInspectable 來對元件做快速設定,但是比較麻煩的是之後再調整時可能需要一個一個調整。

當然你也可以使用 IBDesignable 來新增一個客製化屬性就是了,像是上方的 style 作法,但是沒看過有人有這樣做就是了。 ?


|切換不同環境/版本

常常我們在開發的時候可能會分成 DevelopmentStagingProduction,我們通常會根據這些環境不同來微調某部分的程式碼。舉例來說,像是 API,可能會根據環境不同我們的 baseURL 的網址也會不同,這邊我們有幾種做法來做切換:

1. 使用 Enum 管理

我們也可以寫一個 enum 來管理他們:

2. 使用 branch 處理

當然我們也可以使用 git 分別建立 develop 跟 staging 的分支來處理不同環境的情況,而 master 分支就是處理 production 的情況。

3. 建立 Target

我們可以在 Xcode 中根據環境建立不同的 Target,我們在 Project 的 Generl 下的 TARGETS,可以右鍵點選我們原有的 target 來複製它:

並且建立不同環境下的 Config 的文件:

接著設定這些檔案只屬於特定 Target 下的內容:

之後我們會在每個 Config 文件中編寫相同的結構,只是在 baseURL 中有不同:

之後我們在運行不同的 target 時,我們所取得的 baseURL 也會不同。


Summary

RD 人生

前面也有提到,專案需求會變動是正常的,但要如何用做小的力氣去做到改變多個方面就是一門學問了,以上這些方法都是我在開發的時候學習到的一些小技巧分享給大家,面對需要一直頻繁改變的隕石開發環境,這些方法對我來說蠻實用的 ?。如果有什麼不適當的操作或是更好管理的方式,也歡迎各位讀者與我交流,互相切磋 ??。


上一篇
D2 - 有了 Git 後,讓我們回到過去取暖吧
下一篇
D4 - 使用 IBDesignable 和 IBInspectable 快速製作 UI
系列文
諸神黃昏下的 iOS 工程師31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言